package com.nhim.core.dao;

import java.lang.reflect.ParameterizedType;
import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceException;
import javax.persistence.Query;

import org.springframework.orm.jpa.JpaCallback;
import org.springframework.orm.jpa.support.JpaDaoSupport;

import com.nhim.core.dao.ICoreDAO;

public abstract class CoreDAO<K, E> extends JpaDaoSupport implements ICoreDAO<K,E> {
	protected Class<E> entityClass;

	@SuppressWarnings("unchecked")
	public CoreDAO() {
		ParameterizedType genericSuperclass = (ParameterizedType) getClass()
				.getGenericSuperclass();
		this.entityClass = (Class<E>) genericSuperclass
				.getActualTypeArguments()[1];
	}

	public void save(E entity) {
		logger.debug("saving " + entity + " instance");
		try {
			getJpaTemplate().persist(entity);
			logger.debug("save successful");
		} catch (RuntimeException re) {
			logger.error("save failed", re);
			throw re;
		}
	}

	public void delete(E entity) {
		logger.debug("deleting " + entity + " instance");
		try {
			getJpaTemplate().remove(entity);
			logger.debug("delete successful");
		} catch (RuntimeException re) {
			logger.error("delete failed", re);
			throw re;
		}
	}

	public E saveOrUpdate(E entity) {
		logger.debug("updating " + entity + " instance");
		try {
			E result = getJpaTemplate().merge(entity);
			logger.debug("update successful");
			return result;
		} catch (RuntimeException re) {
			logger.error("update failed", re);
			throw re;
		}
	}

	public E findById(K id) {
		logger.debug("search for element with id: " + id);
		return getJpaTemplate().find(entityClass, id);

	}

	@SuppressWarnings("unchecked")
	public List<E> findAll() {
		@SuppressWarnings("rawtypes")
		Object res = getJpaTemplate().execute(new JpaCallback() {

			public Object doInJpa(EntityManager em) throws PersistenceException {
				Query q = em.createQuery("SELECT h FROM "
						+ entityClass.getName() + " h");
				return q.getResultList();
			}

		});

		return (List<E>) res;
	}

}